<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\LibApi\LibApiController;
use App\Http\Controllers\QrCodeController;
use App\Http\Controllers\ScoreRuleController;
use App\Models\Reservation;
use App\Models\ReservationApply;
use App\Models\ReservationSchedule;
use App\Models\ReservationSeat;
use App\Models\ReservationSpecialSchedule;
use App\Models\UserInfo;
use App\Models\UserLibraryInfo;
use App\Validate\ReservationValidate;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

/**
 * 线下预约类
 */
class ReservationOfflineController extends CommonController
{
    protected $score_type = 5; //积分类型
    protected $model;
    protected $applyModel;
    protected $validate;

    public function __construct()
    {
        parent::__construct();

        $this->model = new Reservation();
        $this->applyModel = new ReservationApply();
        $this->validate = new ReservationValidate();
    }

    /**
     * 手动预约获取预约时间段
     * @param  $reservation_id 文化配送id
     */
    public function getMakeQuantum()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息

        //增加验证场景进行验证
        if (!$this->validate->scene('get_make_quantum')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $id = $this->request->reservation_id;
        $res = $this->model->detail($id);

        if (!$res) {
            return $this->returnApi(201, '参数传递错误');
        }
        $res = $res->toArray();
        $display_day = !empty($res['display_day']) ? $res['display_day'] : 7;

        $data = [];
        $data['make_quantum'] = $this->model->getMakeTime(null, $res, $display_day); //获取排版
        unset($res['reservation_type']);

        $real_info_arr = $this->model->getReservationApplyParam(); //获取所有的数据
        $real_info_arr = $this->getRealInfoArray($res['real_info'], $real_info_arr);
        $real_info = [];
        $real_info[] = ['id' => 4, 'field' => 'reader_id', 'value' => '读者证']; //读者证放在第一列
        if ($real_info_arr) {
            foreach ($real_info_arr as $key => $val) {
                if ($val['field'] !== 'reader_id') {
                    $real_info[] = $val;
                }
            }
        }
        $data['real_info'] = $real_info;
        return $this->returnApi(200, '获取成功', true, $data);
    }


    /**
     * 手动预约时间段
     * @param reservation_id 文化配送id
     * @param schedule_id 排班id
     * @param schedule_type 排班类型
     * @param seat_id   座位id  座位预约必须
     * @param make_time 需要预约时间
     * @param number    多物品预约时的数量  多物品必须 其他可不传
     * @param username  姓名
     * @param id_card  身份证
     * @param tel  电话号码
     * @param reader_id  读者证  必填
     * @param img  头像
     * @param remark  备注 可选  除备注外，其余都是必填
     * @param unit 单位
     * @param age  年龄
     * @param sex  性别  1 男  2 女
     */
    public function makeInfo()
    {
        $this->model->checkApplyStatus(); //处理逾期报名信息

        //增加验证场景进行验证
        if (!$this->validate->scene('make')->check($this->request->all())) {
            return $this->returnApi(201, $this->validate->getError());
        }
        $reader_id = $this->request->reader_id;
        $id = $this->request->reservation_id;

        //限制用户多次点击
        $key = md5('reservation_apply' . $id . request()->ip());
        $oldKey = Cache::get($key); //没有缓存返回false
        if ($oldKey) {
            return $this->returnApi(201, "您操作的太频繁了，请稍后重试");
        } else {
            Cache::put($key, 1, 2);
        }

        //获取读者证号id
        $userLibraryInfoModel = new UserLibraryInfo();
        $account_id = $userLibraryInfoModel->where('account', $reader_id)->value('id');
        if (empty($account_id)) {
            $libApi = new LibApiController();
            $reader_info = $libApi->getReaderInfo($reader_id);
            if ($reader_info['code'] != 200) {
                return $this->returnApi(201, "读者证信息查询失败");
            }
            $userLibraryInfoModel->change($reader_info['content']);
            $account_id = $userLibraryInfoModel->id;
        }

        if (empty($account_id)) {
            return $this->returnApi(201, "读者证号信息查询失败");
        }
        $userInfoModel = new UserInfo();
        $user_id = $userInfoModel->getUserIdByAccount($account_id);

        //查找当前日期是否有特殊时间设置
        $reservationSpecialScheduleModel = new ReservationSpecialSchedule();
        $special_info = $reservationSpecialScheduleModel->getSpecialListByDate($id, $this->request->make_time);
        if ($special_info && count($special_info) == 1 && empty($special_info[0]['start_time']) && empty($special_info[0]['end_time'])) {
            return $this->returnApi(201, $this->request->make_time . " 未开放预约"); //当前不支持预约
        }

        /*检查是否违规*/
        // $validateModel = new UserViolate();
        // $isViolate = $validateModel->checkIsViolate($user_id, 'reservation');
        // if ($isViolate) {
        //     return $this->returnApi(201, '已达到违规次数上限,不能进行此操作');
        // }

        $res_info = $this->model->where('id', $id)->where('is_del', 1)->where('is_play', 1)->first();
        if (empty($res_info)) {
            return $this->returnApi(202, '预约不存在');
        }
        if ($res_info['node'] != 7) {
            $this->request->merge(['make_time' => date('Y-m-d', strtotime($this->request->make_time))]);
        }

        if ($res_info->node == 6 && empty($this->request->seat_id)) {
            return $this->returnApi(201, '座位号不能为空');
        }
        if ($res_info->node == 2) {
            if (empty($this->request->number)) return $this->returnApi(201, '预约数量不能为空');
            if (!empty($res_info->make_max_num) && $this->request->number > $res_info->make_max_num) return $this->returnApi(201, '预约数量不能大于每次限制预约个数');
        }

        //判断是否有不能预约的时间段
        if ($res_info['day_make_time']) {
            if (date('H:i:s') < $res_info['day_make_time']) {
                return $this->returnApi(202, '预约还未开始，请稍后再来');
            }
        }

        //判断当前预约是否有，特殊排版
        if ($res_info['node'] != 7) {
            $reservationSpecialScheduleModel = new ReservationSpecialSchedule();
            $special_info = $reservationSpecialScheduleModel->getSpecialListByDate($id, $this->request->make_time);
            if ($special_info && $this->request->schedule_type == 1) {
                return $this->returnApi(201, "网络异常，请稍后重试");
            }
        }

        //判断是否需要绑定读者证
        // if (config('other.is_validate_lib_api')) {
        //     if ($res_info->is_reader == 1) {
        //         //判断读者证号密码是否正确 和是否绑定读者证
        //         $userLibraryInfoModel = new UserLibraryInfo();
        //         $account_lib_info = $userLibraryInfoModel->checkAccountPwdIsNormal($user_id);
        //         if (is_string($account_lib_info)) {
        //             return $this->returnApi(204, $account_lib_info);
        //         }
        //         $account_id = $account_lib_info['id'];
        //     }
        //     if ($res_info['is_reader'] == 1 && empty($account_id)) {
        //         return $this->returnApi(201, '请先绑定读者证');
        //     }
        // }

        //判断积分是否满足要求
        if (config('other.is_need_score') && $res_info->is_reader == 1) {
            $scoreRuleObj = new ScoreRuleController();
            $score_status = $scoreRuleObj->checkScoreStatus($this->score_type, $user_id, $account_id);
            if ($score_status['code'] == 202 || $score_status['code'] == 203) return $this->returnApi(202, $score_status['msg']);
        }

        //取消预约后10分钟之内不能在预约当前预约（参观预约是不能预约当前座位）
        $selfCancelMakeInfo = $this->applyModel->selfMakeStatus($user_id, $account_id, $id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time, $this->request->seat_id, [2], $res_info['node']);
        if ($selfCancelMakeInfo && $selfCancelMakeInfo['change_time'] > date('Y-m-d H:i:s', strtotime("-10 min"))) {
            return $this->returnApi(202, '取消预约后10分钟之内不能再次预约');
        }
        //判断只能预约几天的数据
        if ($res_info['node'] != 7) {
            $display_day = !empty($res_info['display_day']) ? $res_info['display_day'] : 7;
            $now_time = date('Y-m-d', strtotime("+$display_day day"));
            //不能超过设置的预约天数
            if ($now_time <=  $this->request->make_time || $this->request->make_time < date('Y-m-d')) {
                return $this->returnApi(202, "预约时间段有误，请重新检查");
            }

            $scheduleModel = $this->request->schedule_type == 2 ? new ReservationSpecialSchedule() : new ReservationSchedule();
            $schedule_info = $scheduleModel->where('id', $this->request->schedule_id)->first();
            //判断当前时间段  是否不能预约
            if (date('Y-m-d') == $this->request->make_time && date('H:i:s', strtotime("+30 min")) > $schedule_info['end_time']) {
                return $this->returnApi(202, '预约失败，当前时间段不允许预约');
            }
            if ($res_info->kind == 2 && empty($this->request->number)) {
                return $this->returnApi(202, '预约数量不能为空');
            }
            if ($res_info->kind == 1 && $this->request->number > 1) {
                return $this->returnApi(202, '预约数量不正确');
            }
        }
        //限制预约次数
        if (!empty($res_info->limit_num)) {
            $res_number = $this->applyModel->getReservationNotOutNumber($user_id, $account_id, $id, $res_info['node']);
            if ($res_number >= $res_info->limit_num) {
                return $this->returnApi(202, '您当前预约次数已达到上限');
            }
        }

        DB::beginTransaction();
        try {
            $res_info = $this->model->where('id', $id)->where('is_del', 1)->where('is_play', 1)->lockForUpdate()->first();
            if (empty($res_info)) {
                throw new Exception('预约不存在');
            }
            //如果限制预约次数为空，就要判断自己当前是否预约
            if (($res_info['node'] == 7 && empty($res_info->limit_num)) || $res_info['node'] != 7) {
                //判断自己是否已预约
                $selfStatus = $this->applyModel->selfMakeStatus($user_id, $account_id, $id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time, null, [1, 3, 6], $res_info['node']);
                if ($selfStatus) {
                    throw new Exception('您已预约，请勿重复预约');
                }
            }
            //判断此时间段是否已预约完毕,只要座位号存在，就是已被预约完
            $status = $this->applyModel->makeStatus($id, $this->request->schedule_id, $this->request->schedule_type, $this->request->make_time, $res_info->kind, $res_info->number, $this->request->seat_id, [1, 3, 6], $res_info['node']);
            if ($status !== false && $status <= 0) {
                throw new Exception('当前时间段预约已满，请重新选择');
            }

            if ($res_info->node == 2) {
                if (($status === false &&  $res_info->number < $this->request->number)  || ($status !== false &&  $status < $this->request->number)) {
                    throw new Exception('当前时间段剩余数量已不足，请重新选择');
                }
            }
            $where = [];
            if ($res_info->is_real == 1) {
                if (!empty($res_info->real_info)) {
                    $real_info = explode('|', $res_info->real_info);
                    $where = $this->model->checkApplyParam($res_info, $real_info, $this->request->all());
                }
            }
            //获取预约结束时间
            if ($res_info->node != 7) {
                if ((date('Y-m-d') == date('Y-m-d', strtotime($this->request->make_time)) || date('Y-m-d') == $this->request->make_time) && date('H:i:s') > $schedule_info['start_time']) {
                    $where['expire_time'] = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . "+" . $res_info['clock_time'] . " min"));
                } else {
                    $where['expire_time'] = date('Y-m-d H:i:s', strtotime($this->request->make_time . ' ' . $schedule_info['start_time'] . " +" . $res_info['clock_time'] . " min"));
                }
            } else {
                $where['expire_time'] = date('Y-m-d H:i:s', strtotime(date('Y-m-d H:i:s') . "+" . $res_info['clock_time'] . " min"));
            }

            //检查是否需要审核
            $where['status'] = $res_info['is_approval'] == 1 ? 3 : 1;

            $where['schedule_id'] = $this->request->schedule_id;
            $where['schedule_type'] = $this->request->schedule_type;
            $where['number'] = $this->request->number ? $this->request->number : 1;
            $where['account_id'] = !empty($account_id) ? $account_id : 0;
            $where['user_id'] = !empty($user_id) ? $user_id : 0; //微信报名增加
            $where['score'] = !empty($score_status['score_info']['score']) ? $score_status['score_info']['score'] : 0;
            $where['reservation_id'] = $id;
            $where['make_time'] =  $res_info->node != 7 ? $this->request->make_time : date('Y-m-d');
            $where['seat_id'] = ($res_info->node == 6 || ($res_info->node == 7 && $res_info->sign_way == 2)) ? $this->request->seat_id : null;
            $where['make_way'] = 2; //管理员手动预约

            $qrCodeObj = new QrCodeController();
            $serial_number = $qrCodeObj->getQrCode('reservation_apply', 'serial_number');
            $where['serial_number'] = $serial_number;

            // $this->applyModel->add($where, ['user_id', 'account_id', 'reservation_id', 'schedule_id', 'make_time', 'remark', 'status', 'number', 'expire_time', 'tel', 'unit', 'remark', 'id_card', 'sex', 'age', 'score', 'seat_id']);
            $this->applyModel->add($where);

            // $number = $this->request->number ? $this->request->number : 1;
            $res_info->apply_number = $res_info->apply_number + 1; //已预约次数，不然设备预约有问题
            $res_info->save(); //添加预约数量

            $msg = $res_info->is_approval == 1 ? "提交" : '申请';
            $system_id = $this->systemAdd('场馆预约申请', $user_id, $account_id, 30, intval($this->applyModel->id), '您的场馆预约申请：【' . $res_info->name . '】' . $msg . '成功！');

            /**执行积分规则 */
            if (!empty($score_status['code']) && $score_status['code'] == 200) {
                $scoreRuleObj->scoreChange($score_status, $user_id, $account_id, $system_id); //添加积分消息
            }

            DB::commit();
            return $this->returnApi(200, '预约成功', true);
        } catch (\Exception $e) {
            DB::rollBack();
            //   return $this->returnApi(202, $e->getMessage() . $e->getFile() . $e->getLine());
            // $msg = $e->getCode() == 2002 ? $e->getMessage() : '预约失败';
            return $this->returnApi(202, $e->getMessage());
        }
    }
}
